#ifndef TRANSFORMABLE_H
#define TRANSFORMABLE_H

#include <limits>

// 简化调用宏
#define TRANS Transformable::getInstance()

class Transformable 
{
public:
    // 禁止拷贝与赋值
    Transformable(const Transformable&) = delete;
    Transformable& operator=(const Transformable&) = delete;

    // 获取单例
    static Transformable* const getInstance() 
    {
        static Transformable instance;
        return &instance;
    }

    // 像素坐标 --> 地图坐标（X向）
    void pixelToMapX(double px, double& x) const
    {
        x = px * meters_per_pixel + base_x;   
    } 

    // 像素坐标 --> 地图坐标 (Y向)
    void pixelToMapY(double py, double& y) const
    {
        y = (_height - py) * meters_per_pixel + base_y;
    }

    // 像素坐标 --> 地图坐标
    void pixelToMap(double px, double py, double& x, double& y) const
    {
        pixelToMapX(px, x);
        pixelToMapY(py, y);
    }

    // 像素距离 --> 地图距离
    void pixelLenInMap(double plen, double& len) const 
    {
        len = plen * meters_per_pixel;
    }

    // 地图坐标 --> 像素坐标 (X向)
    void mapToPixelX(double x, double& px) const 
    {
        px = (x - base_x) / meters_per_pixel;
    }

    // 地图坐标 --> 像素坐标 (Y向)
    void mapToPixelY(double y, double& py) const
    {
        py = _height - (y - base_y) / meters_per_pixel;
    }

    // 地图坐标 --> 像素坐标
    void mapToPixel(double x, double y, double& px, double& py) const
    {
        mapToPixelX(x, px);
        mapToPixelY(y, py);
    }

    // 地图距离 --> 像素距离
    void mapLenInPixel(double len, double& plen) const
    {
        plen = len /  meters_per_pixel;
    }

    // 获取缩放比例
    double scale() const {
        return meters_per_pixel;
    }

    // 设置缩放比例
    void setScale(double s) {
        meters_per_pixel = s;
    }

    // 获取基准位置
    void base(double& x, double& y) const
    {
        x = base_x;
        y = base_y;
    }

    // 设置基准点
    void setBase(double x, double y) 
    {
        base_x = x;
        base_y = y;
    }

    // 获取光标像素位置
    void cursorInPixel(double& px, double& py) const
    {
        px = cx_pixel;
        py = cy_pixel;
    }

    // 获取光标地图位置
    void cursorInMap(double& x, double& y) const 
    {
        x = cx_map;
        y = cy_map;
    }

    // 获取窗口宽度
    double width() const
    {
        return _width;
    }

    // 获取窗口高度
    double height() const
    {
        return _height;
    }

    // 获取地图边界
    void limits(double& top, double& bottom, double& left, double& right) const
    {
        top     = limit_top;
        bottom  = limit_bottom;
        left    = limit_left;
        right   = limit_right;
    }

    // 设置地图边界
    void setLimits(double top, double bottom, double left, double right)
    {
        if (top <= bottom || left <= right) return;

        limit_top       = top;
        limit_bottom    = bottom;
        limit_left      = left;
        limit_right     = right;
    }

    // 获取最小比例尺
    double minimumScale() const 
    {
        return minimum_scale_radios;
    }

    // 设置最小比例尺
    void setMinimumScale(double s)
    {
        minimum_scale_radios = s;
    }

    // 获取最大比例尺
    double maximumScale() const
    {
        return maximum_scale_radios;
    }

    // 设置最大比例尺
    void setMaximumScale(double s)
    {
        maximum_scale_radios = s;
    }

    // 获取窗口中心点地图坐标
    void center(double& x, double& y) const
    {
        pixelToMap(_width / 2, _height / 2, x, y);
    }

    // 设置屏幕中心点地图坐标
    void setCenter(double x, double y)
    {
        // 超界判定
        if (x < limit_left || x > limit_right || y < limit_bottom || y > limit_top) return;

        base_x = x - 0.5 * _width * meters_per_pixel;
        base_y = y - 0.5 * _height * meters_per_pixel;
    }

    // 开始移动地图（按自定义条件触发该函数）
    void beginMove(double px, double py) 
    {
        base_move_flag = 1;
        
        cx_pixel = px;
        cy_pixel = py;

        pixelToMap(cx_pixel, cy_pixel, cx_map, cy_map);
    }

    // 结束移动地图（要与开始条件相对应）
    void endMove(double px, double py)
    {
        base_move_flag = 0;
        
        cx_pixel = px;
        cy_pixel = py;

        pixelToMap(cx_pixel, cy_pixel, cx_map, cy_map);
    }

    // 缩放地图（按自定义条件触发，缩放平移条件不可同时满足）
    void doScale(double px, double py, int angleDeltaY)
    {
        if (base_move_flag == 1) return;

        double _cx_map, _cy_map, cx_map_, cy_map_;
        // 缩放前位置
        pixelToMap(px, py, _cx_map, _cy_map);

        if (angleDeltaY > 0)
        {
            // 缩小比例尺（放大）
            if (meters_per_pixel / scale_factor > minimum_scale_radios)
            {
                meters_per_pixel /= scale_factor;
            }
        }
        else 
        {
            // 放大比例尺（缩小）
            if (meters_per_pixel * scale_factor < maximum_scale_radios)
            {
                meters_per_pixel *= scale_factor;
            }
        }

        // 缩放后位置
        pixelToMap(px, py, cx_map_, cy_map_);
        // 更新基准
        base_x -= (cx_map_ - _cx_map);
        base_y -= (cy_map_ - _cy_map);
    }

    // 处理光标移动（光标移动时应总是触发该函数）
    void handleMouseMove(double px, double py)
    {
        cx_pixel = px;
        cy_pixel = py;

        if (base_move_flag)
        {
            double _cx_map, _cy_map, delta_x, delta_y;
            pixelToMap(cx_pixel, cy_pixel, _cx_map, _cy_map);

            delta_x = _cx_map - cx_map;
            delta_y = _cy_map - cy_map;

            // 超界判定
            double top, bottom, left, right;
            pixelToMap(0, _height, left, bottom);
            pixelToMap(_width, 0, right, top);

            if (left < limit_left) 
            {
                if (delta_x > 0) delta_x = 0;
            }
            if (right > limit_right)
            {
                if (delta_x < 0) delta_x = 0;
            } 
            if (bottom < limit_bottom)
            {
                if (delta_y > 0) delta_y = 0;
            }
            if (top > limit_top)
            {
                if (delta_y < 0) delta_y = 0;
            }

            base_x -= delta_x;
            base_y -= delta_y;
        }
        pixelToMap(cx_pixel, cy_pixel, cx_map, cy_map);
    }

    // 处理窗口变化（窗口大小发生变化时应总是触发该函数）
    void handleResize(double w, double h)
    {
        _width  = w;
        _height = h;
    }

private:
    // 私有化构造函数
    Transformable() {};
    ~Transformable() = default;

    // 缩放系数（米/像素）
    double meters_per_pixel     = 0.1;
    // 缩放因子
    double scale_factor         = 1.2;
    // 基准点（初始原点位于屏幕左下角点，x向右，y向上）
    double base_x               = 0;
    double base_y               = 0;

    // 基准移动标志
    int base_move_flag          = 0;

    // 光标像素位置
    double cx_pixel     = 0;
    double cy_pixel     = 0;

    // 光标地图位置
    double cx_map       = 0;
    double cy_map       = 0;

    // 窗口大小
    double _width       = 600;
    double _height      = 600;

    // 地图边界
    double limit_top    = std::numeric_limits<double>::infinity(); // 上
    double limit_bottom = -std::numeric_limits<double>::infinity(); // 下
    double limit_right  = std::numeric_limits<double>::infinity(); // 右
    double limit_left   = -std::numeric_limits<double>::infinity(); // 左

    // 比例尺约束
    double minimum_scale_radios = 0.002;
    double maximum_scale_radios = 1.0;
};

#endif